約 6,216,730 件
https://w.atwiki.jp/vst_prog/pages/91.html
トップページ CMidiMsgクラスの実装 ここでは前項で定義したCMidiMsgクラスについて説明する。 CMidiMsgクラスの実装 CMidiMsgクラスではコンストラクタでclearMidiMsg()関数を呼び出し初期化している。 clearMidiMsg()関数はメンバー変数に初期値を代入している。終了処理はないため、デストラクタでは何もしていない。 CMidiMsg CMidiMsg(void){clearMidiMsg();} CMidiMsg ~CMidiMsg(void){} void CMidiMsg clearMidiMsg(){// メンバー変数を初期化するcur=0;num=0;memset(buf, 0, sizeof(MidiMessage)*MIDIMSG_MAXNUM);} CMidiMsgクラス addMidiMsg()関数 次にaddMidiMsg()関数について説明する。 メンバ関数 戻り値 引数 内容 addMidiMsg() int VstMidiEvent *midievent MIDIメッセージをMIDIバッファへの保存する関数。引数は受け取るMIDIメッセージ(VstMidiEvent型のポインタ)MIDIバッファへの追加に成功すると1、失敗すると0が返る。 この関数はVSTから受け取ったMIDIメッセージをMIDIバッファへ保存するための関数で、processEvents()関数内で、下記のように呼び出されることを想定している。 VstInt32 MyMidiSample2VST processEvents (VstEvents* events){// MIDIバッファを初期化。clearMidiMsg(); int loops = (events- numEvents); // VSTイベントの回数だけループをまわす。for (int i = 0;i loops; i++){// 与えられたイベントがMIDIならばMIDIバッファに追加する。if ((events- events[i])- type == kVstMidiType){VstMidiEvent *midievent = (VstMidiEvent*)(events- events[i]);if( !addMidiMsg(midievent) ){break;}}} // 1を返さなければならないreturn 1;} processEvents()関数内では、はじめにclearMidiMsg()関数でMIDIバッファ初期化している。 (clearMidiMsg()関数についてはコンストラクタの部分で説明したとおりである。) 次にVSTイベント(VstEvents* events)がいくつあるか確認し、VSTイベントの数だけ繰返し(for文)をおこない、VSTイベントがMIDIメッセージの場合にaddMidiMsg()関数を使用して、MIDIバッファへ保存している。 addMidiMsg()関数は下記のようにMIDIバッファに空きがあるかを確認し、空きがあればMIDIバッファに保管する。保管後は、MIDIバッファ内のMIDIメッセージ数を更新するようにしている。 また、VSTホストからMIDIメッセージを受け取る際はVstMidiEvent型で渡されることを想定し、簡単に処理できるようにaddMidiMsg()関数をオーバーロードしている。 int CMidiMsg addMidiMsg(VstMidiEvent *midievent){// VstMidiEventからMidiMessgeへデータをコピーするMidiMessage tmp;tmp.deltaFrames = midievent- deltaFrames;tmp.message = midievent- midiData[0] 0xF0;tmp.channel = midievent- midiData[0] 0x0F;tmp.data1 = midievent- midiData[1];tmp.data2 = midievent- midiData[2]; return addMidiMsg(tmp);} int CMidiMsg addMidiMsg(MidiMessage msg){// バッファがいっぱいなら0を返すif (num = MIDIMSG_MAXNUM)return 0; // バッファにMIDIメッセージを保存buf[num] = msg; // バッファに保存されているMIDIメッセージの数を増やす。num++;if (num MIDIMSG_MAXNUM) {num = MIDIMSG_MAXNUM;} return 1;} CMidiMsgクラス getMidiMsg()関数、getMidiMessageNum()関数、getNextDeltaFrames()関数 【作成中】 MIDIメッセージ処理用クラス定義 【作成中】 ここで作成するVSTサンプルのソースコード全体はここにある。 次へ 同一カテゴリのTips 項目 No. 概要 MIDIメッセージ処理 No.1 MIDIメッセージ処理で最小構成の自作VSTに追加する変数・関数 No.2 VSTの初期化とMIDIメッセージ処理関連の変数の初期化 No.3 ホストアプリケーションからMIDIメッセージを受け取る方法 No.4 MIDIメッセージをprocessReplacing()関数中で処理する方法 No.5 MIDIメッセージ処理で作成したVSTのサンプルソースコード全体(暫定版)
https://w.atwiki.jp/vst_prog/pages/74.html
トップページ MIDIメッセージ処理 MIDIメッセージにあわせて動作するVSTのサンプルである。 下記VSTはSynthとしてロードされ、常にノイズを発生させる。実行時は音量に注意してほしい。 ノイズのボリュームをMIDI CC7でコントロールできる。 サンプルコード全体 ソースコードのダウンロード→ここをクリック // ============================================================================================// インクルードファイル// ============================================================================================#include stdlib.h #include string.h #include "audioeffectx.h" // ============================================================================================// 設計情報の記入// ============================================================================================#define MY_VST_INPUT_NUM 2 //入力数。モノラル入力=1、ステレオ入力=2#define MY_VST_OUTPUT_NUM 2 //出力数。モノラル出力=1、ステレオ出力=2 #define MY_VST_UNIQUE_ID SMPL //ユニークID //公開する場合は以下URLで発行されたユニークIDを入力する。 //http //ygrabit.steinberg.de/~ygrabit/public_html/index.html #define MY_VST_PRESET_NUM 1 //プリセットプログラムの数#define MY_VST_PARAMETER_NUM 0 //パラメータの数 // ============================================================================================// MIDI処理用の定義// ============================================================================================#define MIDIMSG_MAXNUM 255 struct MidiMessage{VstInt32 deltaFrames; //MIDIメッセージを処理するタイミングunsigned char message; //MIDIメッセージ番号unsigned char channel; //MIDIチャンネルunsigned char data1; //MIDIデータ1unsigned char data2; //MIDIデータ2}; // ============================================================================================// VSTの基本となるクラス// ============================================================================================class MyMidiSampleVST public AudioEffectX{protected int midimsgnum; //受け取ったMIDIメッセージの数MidiMessage midimsgbuf[MIDIMSG_MAXNUM]; //受け取ったMIDIメッセージを保管するバッファ // ノイズのボリュームfloat volume;public MyMidiSampleVST (audioMasterCallback audioMaster); // 音声信号を処理するメンバー関数virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames); // MIDIメッセージをホストアプリケーションから受け取るためのメンバー関数VstInt32 processEvents (VstEvents* events);}; // ============================================================================================// このVSTのを生成するための関数// ============================================================================================AudioEffect* createEffectInstance (audioMasterCallback audioMaster){//newでこのVSTを生成したポインタを返すreturn new MyMidiSampleVST (audioMaster);} MyMidiSampleVST MyMidiSampleVST (audioMasterCallback audioMaster) AudioEffectX (audioMaster, MY_VST_PRESET_NUM, MY_VST_PARAMETER_NUM){//VSTの初期化を行う。 //以下の関数を呼び出して入力数、出力数等の情報を設定する。//必ず呼び出さなければならない。setNumInputs (MY_VST_INPUT_NUM); //入力数の設定setNumOutputs (MY_VST_OUTPUT_NUM); //出力数の設定setUniqueID (MY_VST_UNIQUE_ID); //ユニークIDの設定 isSynth (true); //このVSTがSynthかどうかのフラグを設定。 //Synthの場合…true、Effectorの場合…false canProcessReplacing (); //このVSTが音声処理可能かどうかのフラグを設定。 //音声処理を行わないVSTはないので必ずこの関数を呼び出す。 //上記の関数を呼び出した後に初期化を行うmidimsgnum = 0;memset(midimsgbuf, 0, sizeof(MidiMessage) * MIDIMSG_MAXNUM); volume = 1.0f;} void MyMidiSampleVST processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames){//入力、出力は2次元配列で渡される。//入力は-1.0f~1.0fの間で渡される。//出力は-1.0f~1.0fの間で書き込む必要がある。//sampleFramesが処理するバッファのサイズfloat* outL = outputs[0]; //出力 左用float* outR = outputs[1]; //出力 右用 // midieventlistの読み込み位置int midimsg_cursol = 0; for (int i = 0; i sampleFrames; i++){//ここで音声処理を行う。 // MIDIメッセージがあるか確認if ( midimsgnum 0){// MIDIメッセージを処理するタイミングかどうかを確認する。if( midimsgbuf[midimsg_cursol].deltaFrames = i){// MIDIメッセージがコントロールチェンジのボリューム変更(CC7)であった場合if( midimsgbuf[midimsg_cursol].message == 0xB0 midimsgbuf[midimsg_cursol].data1 == 7){volume = (float)( midimsgbuf[midimsg_cursol].data2) / 127.0f;} // midimsgbufからMIDIメッセージを読み出したので// 読み込み位置を進め、MIDIメッセージの数を減らすmidimsgnum--;midimsg_cursol++;}} //出力バッファへ書き込む。outL[i] = volume * (float)((rand() % 256) -128) / 255.0f;outR[i] = volume * (float)((rand() % 256) -128) / 255.0f;}} // MIDIメッセージを処理するメンバー関数// processReplacing()の前に必ず1度だけ呼び出される。// VstInt32 MyMidiSampleVST processEvents (VstEvents* events){// MIDIのリストを初期化します。midimsgnum = 0;memset(midimsgbuf, 0, sizeof(MidiMessage) * MIDIMSG_MAXNUM); // VSTイベントの回数だけループをまわす。int loops = (events- numEvents);for (int i = 0;i loops; i++){// 与えられたイベントがMIDIならばmidimsgbufにストックするif ((events- events[i])- type == kVstMidiType){VstMidiEvent *midievent = (VstMidiEvent*)(events- events[i]); midimsgbuf[midimsgnum].deltaFrames = midievent- deltaFrames;midimsgbuf[midimsgnum].message = midievent- midiData[0] 0xF0; // MIDIメッセージmidimsgbuf[midimsgnum].channel = midievent- midiData[0] 0x0F; // MIDIチャンネルmidimsgbuf[midimsgnum].data1 = midievent- midiData[1]; // MIDIデータ1midimsgbuf[midimsgnum].data2 = midievent- midiData[2]; // MIDIデータ2midimsgnum++; // MIDIメッセージのバッファがいっぱいの場合はループを打ち切る。if (i = MIDIMSG_MAXNUM){break;}}} // 1を返しておくreturn 1;} VST Tipsトップページへ 同一カテゴリのTips 項目 No. 概要 MIDIメッセージ処理 No.1 MIDIメッセージ処理で最小構成の自作VSTに追加する変数・関数 No.2 VSTの初期化とMIDIメッセージ処理関連の変数の初期化 No.3 ホストアプリケーションからMIDIメッセージを受け取る方法 No.4 MIDIメッセージをprocessReplacing()関数中で処理する方法 No.5 MIDIメッセージ処理で作成したVSTのサンプルソースコード全体(暫定版)
https://w.atwiki.jp/vst_prog/pages/55.html
VST Tips(準備中) VC++ プロジェクトの作成 ここではVC++でVST用のプロジェクトを作成する方法については記載する。 Visual C++ プロジェクト作成ウィザードの起動 Visual C++を起動し、メニューから「ファイル」→「新規作成」→「プロジェクト」を選択する。 プロジェクト作成ウィザードが起動する。 プロジェクト種別、プロジェクト名の入力 開いたダイアログのテンプレートから「Win32 プロジェクト」を選択。 ダイアログ下側の「プロジェクト名」に今回作成するプロジェクトの名前を入力し、「OK」を押す。 プロジェクト種別の確認 現在のプロジェクト設定が「Windowsアプリケーション」となっていることを確認し、「次へ」を押す アプリケーションの設定 アプリケーションの種類で「DLL」を選択。追加オプションとして「空のプロジェクト」を選択して完了を押す。 完了を押すとプロジェクトが作成される。 次へ 同一カテゴリのTips 項目 No. 概要 VC++ プロジェクトの準備 No.1 VC++でVST用のプロジェクトを作成する No.2 VSTを作成するに当たって必要なVST SDKファイルをVC++のプロジェクトに追加する No.3 VSTを作成するに当たって必要なvstplug.defファイルを作成する No.4 VSTを作成するに当たって必要なコンパイラ、リンカ設定を追加する No.5 VSTをコンパイルするの際の注意事項
https://w.atwiki.jp/vst_prog/pages/70.html
VST Tips(準備中) 最小構成のVST ここでは最小構成のVSTを作成する方法について記載する。 最小構成のVSTを作成するには以下の2点を行えば、VSTとして読み込めるものが完成する。 AudioEffectXクラスを継承した自作クラスの作成 自分で作ったVSTクラスを呼び出すAudioEffect* createEffectInstance()関数の作成 なお、ここで作成するVSTサンプルのソースコード全体はここにある。 AudioEffectXクラスを継承した自作VST用クラスの作成 まず基本として、VSTはAudioEffectXクラスを継承して作らなければならない。 AudioEffectXクラスは「vstsdk2.4\public.sdk\source\vst2.x\audioeffectx.h」で定義されている。 AudioEffectXクラスを継承して作った自作クラスは、以下の2つの関数を持たなければならない。 コンストラクタ …自作VSTの初期化を行う。初期化にはルールがある(後述)。 void processReplacing() …音声の処理を行う関数。AudioEffectXクラスから継承する。 具体的には以下のようになる。 // ============================================================================================// VSTの基本となるクラス// ============================================================================================class MyMinimumVST public AudioEffectX{public MyMinimumVST (audioMasterCallback audioMaster); // 音声信号を処理するメンバー関数virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames);}; AudioEffect* createEffectInstance()関数の作成 次に、ホストアプリケーション(Cubase,Sonar等)が自作VSTのインスタンスを作成するために必要な関数を作成しなければならない。 なぜこのような関数が必要かの詳細は説明できるほどの知識がないため省略する。(どうもDLLファイルはC++のクラスをエクスポートできないらしい。苦肉の策としてこのような関数がある模様。) 自作VSTのインスタンスをnewで生成してreturnで返すだけでよい。 // ============================================================================================// 自作VSTのを生成するための関数// ============================================================================================AudioEffect* createEffectInstance (audioMasterCallback audioMaster){//newでこのVSTを生成したポインタを返すreturn new MyMinimumVST (audioMaster);} 自作VSTクラスの初期化方法、音声処理部分の説明については次項で説明する。 次へ 同一カテゴリのTips 項目 No. 概要 最小構成のVST No.1 最小構成の自作VSTに必要な関数等の説明。 No.2 最小構成の自作VSTの必須初期化項目について No.3 最小構成の自作VSTの音声処理関数について No.4 最小構成の自作VSTのサンプルソースコード全体
https://w.atwiki.jp/vst_prog/pages/77.html
トップページ MIDIメッセージをホストアプリケーションから受け取る関数 MIDIメッセージをホストアプリケーションから受け取るにはprocessEvents()関数を利用する。 processEvents()関数 VstInt32 processEvents (VstEvents* events) 戻り値と引数については以下のとおりである。 戻り値(型) 説明 VstInt32 戻り値についてはホストアプリケーションで無視される。ただし、念のため1を返すようにするとよい。 引数 説明 VstEvents* events イベントを保持しているVstEvents型変数(後述)へのポインタ processEvents()関数はMIDIメッセージだけを受け取る関数ではなく、VSTに関するホストアプリケーションからのイベントをすべて受け取る関数となっている。 ただし、実装されているメッセージは現在(2010年11月)のところMIDIに関する以下の2つだけである。 MIDIメッセージ MIDI System Exclusiveメッセージ processEvents()関数との関係 ホストアプリケーションはprocessReplacing()関数を呼び出す前に必ず1度だけprocessEvents()関数呼び出し、イベントをVSTに通知する。 また、processEvents()関数で渡されるイベントは直後に呼び出すprocessReplacing()関数に関連するイベントのみとなっている。 ホストアプリケーション側の処理のイメージとしては以下のような感じである。 【ホストアプリケーションの動作】 ①processEvents()関数呼び出し ↓ ②processReplacing()関数呼び出し ↓ ③いろいろ処理 ↓ ④processEvents()関数呼び出し ↓ ⑤processReplacing()関数呼び出し ↓ ⑥いろいろ処理 ↓ ⑦processEvents()関数呼び出し ↓ ⑧processReplacing()関数呼び出し ↓ : : ホストアプリケーションは①でprocessEvents()関数を呼び出した際に、②processReplacing()関数に関連するイベントのみをVSTに渡す。 (ホストアプリケーションは②に無関係のイベント(⑤や⑧に関連するイベント)については渡してはいけない。) サンプルコード processEvents()関数でMIDIメッセージを保存するサンプルコードは以下のとおり。 VstInt32 MyMidiSampleVST processEvents (VstEvents* events){// MIDIのリストを初期化します。midimsgnum = 0;memset(midimsgbuf, 0, sizeof(MidiMessage) * MIDIMSG_MAXNUM); // VSTイベントの回数だけループをまわす。int loops = (events- numEvents);for (int i = 0;i loops; i++){// 与えられたイベントがMIDIならばmidimsgbufにストックするif ((events- events[i])- type == kVstMidiType){VstMidiEvent *midievent = (VstMidiEvent*)(events- events[i]); midimsgbuf[midimsgnum].deltaFrames = midievent- deltaFrames;midimsgbuf[midimsgnum].message = midievent- midiData[0] 0xF0; // MIDIメッセージmidimsgbuf[midimsgnum].channel = midievent- midiData[0] 0x0F; // MIDIチャンネルmidimsgbuf[midimsgnum].data1 = midievent- midiData[1]; // MIDIデータ1midimsgbuf[midimsgnum].data2 = midievent- midiData[2]; // MIDIデータ2midimsgnum++; // MIDIメッセージのバッファがいっぱいの場合はループを打ち切る。if (i = MIDIMSG_MAXNUM){break;}}} // 1を返しておくreturn 1;} サンプルコードの解説 まず引数のVstEvents構造体は以下のように定義されている。 変数 型 説明 numEvents VstInt32 VSTイベントの数。 reserved VstIntPtr 使われていない変数。0で固定 events [2] VstEvent * VSTイベントへのポインタ。numEvents分だけVSTイベントが格納されている。 ホストアプリケーションからのVSTイベント自体は上記のVstEvents構造体のVstEvent * events[]に格納されている。 VstEvent構造体は以下のように定義されている。 変数 型 説明 type VstInt32 VSTイベントのタイプ。実装されているタイプは以下の2つのみ。kVstMidiType…data[ ]に保存されているデータがMIDIメッセージであることを示すkVstSysExType…data[ ]に保存されているデータがMIDI System Exclusiveメッセージであることを示す byteSize VstInt32 VstEvent構造体のtypeとbyteSizeを除いたバイト数。24固定。 deltaFrames VstInt32 processReplacing()関数内でMIDIメッセージの処理タイミング。0~sampleFramesの範囲の値を持つ。 flags VstInt32 使われていない変数。 data[16] char 実際のVSTイベントデータ。typeよって内容が変わる。 サンプルコードでは、最初にMIDIメッセージを保存するバッファを初期化している。(3~5行目) midimsgnum = 0; memset(midimsgbuf, 0, sizeof(MidiMessage) * MIDIMSG_MAXNUM); 次にVSTイベントの数だけ処理するループを作成している。(8~29行目) // VSTイベントの回数だけループをまわす。 int loops = (events- numEvents); for (int i = 0;i loops; i++) { : : } ループの中で与えられたVSTイベントがMIDIメッセージか確認し、MIDIメッセージならばバッファに保存する(12~28行目) バッファに保存する際、VstEvent構造体のままでは扱いにくいため、VstMidiEvent構造体(後述)に型変換している。 if ((events- events[i])- type == kVstMidiType) { VstMidiEvent *midievent = (VstMidiEvent*)(events- events[i]); midimsgbuf[midimsgnum].deltaFrames = midievent- deltaFrames; midimsgbuf[midimsgnum].message = midievent- midiData[0] 0xF0; // MIDIメッセージ midimsgbuf[midimsgnum].channel = midievent- midiData[0] 0x0F; // MIDIチャンネル midimsgbuf[midimsgnum].data1 = midievent- midiData[1]; // MIDIデータ1 midimsgbuf[midimsgnum].data2 = midievent- midiData[2]; // MIDIデータ2 midimsgnum++; } VstMidiEvent構造体については以下のように定義されている。 変数 型 説明 type VstInt32 VstEvent構造体と同じ。 byteSize VstInt32 VstEvent構造体と同じ。 deltaFrames VstInt32 VstEvent構造体と同じ。 flags VstInt32 使われていない変数。 noteLength VstInt32 用途不明 noteOffset VstInt32 用途不明 midiData [4] char MIDIメッセージ。midiData[0]…MIDIステータス(メッセージ)とMIDIチャンネルが入っている。midiData[1]…MIDIメッセージのデータ1midiData[2]…MIDIメッセージのデータ2midiData[3]…将来的な拡張のため予約。0が入っている。 detune char 用途不明。-64~+63の値が入っている。 noteOffVelocity char 用途不明。0~127の値が入っている。 reserved1 char 将来的な拡張のため予約。0が入っている reserved2 char 将来的な拡張のため予約。0が入っている 次へ 同一カテゴリのTips 項目 No. 概要 MIDIメッセージ処理 No.1 MIDIメッセージ処理で最小構成の自作VSTに追加する変数・関数 No.2 VSTの初期化とMIDIメッセージ処理関連の変数の初期化 No.3 ホストアプリケーションからMIDIメッセージを受け取る方法 No.4 MIDIメッセージをprocessReplacing()関数中で処理する方法 No.5 MIDIメッセージ処理で作成したVSTのサンプルソースコード全体(暫定版)
https://w.atwiki.jp/vst_prog/pages/76.html
トップページ VSTクラスの初期化 ここでは前項で定義したMyMidiSampleVSTの初期化を行う。 VSTとしての最低限の初期化を行うとともに以下2つのMIDIに関するメンバー変数を初期化する。 midimsgnum … 受け取ったMIDIメッセージの数。0に初期化しておく midimsgbuf[ ] … 受け取ったMIDIメッセージを保管するバッファ。バッファすべてを0に初期化しておく サンプルコード サンプルコードは以下のとおり。 MyMidiSampleVST MyMidiSampleVST (audioMasterCallback audioMaster) AudioEffectX (audioMaster, MY_VST_PRESET_NUM, MY_VST_PARAMETER_NUM){//VSTの初期化を行う。 //以下の関数を呼び出して入力数、出力数等の情報を設定する。//必ず呼び出さなければならない。setNumInputs (MY_VST_INPUT_NUM); //入力数の設定setNumOutputs (MY_VST_OUTPUT_NUM); //出力数の設定setUniqueID (MY_VST_UNIQUE_ID); //ユニークIDの設定 isSynth (true); //このVSTがSynthかどうかのフラグを設定。 //Synthの場合…true、Effectorの場合…false canProcessReplacing (); //このVSTが音声処理可能かどうかのフラグを設定。 //音声処理を行わないVSTはないので必ずこの関数を呼び出す。 //上記の関数を呼び出した後に初期化を行うmidimsgnum = 0;memset(midimsgbuf, 0, sizeof(MidiMessage) * MIDIMSG_MAXNUM); volume = 1.0f;} サンプルコードの解説 まず2行目~17行目でVSTの初期化を行っている。(詳細はVST初期化ルールのとおり) なお、Synthとして動作させるため、isSynth()関数にtrueを引き渡している。 isSynth (true); //このVSTがSynthかどうかのフラグを設定。 次に19~20行目で2つのMIDIに関するメンバー変数を初期化している。 midimsgnum = 0; memset(midimsgbuf, 0, sizeof(MidiMessage) * MIDIMSG_MAXNUM); 次へ 同一カテゴリのTips 項目 No. 概要 MIDIメッセージ処理 No.1 MIDIメッセージ処理で最小構成の自作VSTに追加する変数・関数 No.2 VSTの初期化とMIDIメッセージ処理関連の変数の初期化 No.3 ホストアプリケーションからMIDIメッセージを受け取る方法 No.4 MIDIメッセージをprocessReplacing()関数中で処理する方法 No.5 MIDIメッセージ処理で作成したVSTのサンプルソースコード全体(暫定版)
https://w.atwiki.jp/vst_prog/pages/84.html
VST Tips(準備中) 簡単な音源(VSTi)の作成(暫定版) (2011/4/14更新) 【注意】 本サンプルはSynthesizerの基本的な処理を追いやすくするために書かれたコードです。以下の点が大きなバグとして残っておりますのでご注意ください。(小さなバグも多数あります) ノートOFF時に振幅が急激に変化するため、不快なノイズが入ります。(基本的には問題ないと思いますが大きな音量の場合、耳やスピーカーを痛める可能性があります。) なお、本サンプル利用を使用したことによって生じたすべての障害・損害・不具合等に関しては、一切の責任を負いません。各自の責任においてご使用ください。 サンプルコード全体 ソースコードのダウンロード→ ここをクリック (dllファイルも同梱しております。dllファイルのウィルスチェックはしておりませんのでdllファイル利用の前には必ずチェックをお願いいたします。) MIDIの処理部分についてはこちらの【CMidiMsg.h】と【CMidiMsg.cpp】をご覧ください。 【MySynthSampleVST.h】 // ============================================================================================// インクルードファイル// ============================================================================================#include stdlib.h #include "audioeffectx.h" #include "CMidiMsg.h"#include "CVoice.h" // ============================================================================================// 設計情報の記入// ============================================================================================#define MY_VST_INPUT_NUM 2 //入力数。モノラル入力=1、ステレオ入力=2#define MY_VST_OUTPUT_NUM 2 //出力数。モノラル出力=1、ステレオ出力=2 #define MY_VST_UNIQUE_ID SMPL //ユニークID //公開する場合は以下URLで発行されたユニークIDを入力する。 //http //ygrabit.steinberg.de/~ygrabit/public_html/index.html #define MY_VST_PRESET_NUM 1 //プリセットプログラムの数#define MY_VST_PARAMETER_NUM 0 //パラメータの数 #define MAX_OSCILLATORS 8 // オシレータの数(最大発音数)// ============================================================================================// VSTの基本となるクラス// ============================================================================================class MySynthSampleVST public AudioEffectX , public CMidiMsg{protected CVoice osc[MAX_OSCILLATORS];public MySynthSampleVST (audioMasterCallback audioMaster); // 音声信号を処理するメンバー関数virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames);virtual void processReplacing2 (float* inL, float* inR, float* outL, float* outR, VstInt32 sampleFrames); // MIDIメッセージをホストアプリケーションから受け取るためのメンバー関数VstInt32 processEvents (VstEvents* events); virtual void onMidiKeyOn (unsigned char channel, unsigned char noteNo, unsigned char velo);virtual void onMidiKeyOff (unsigned char channel, unsigned char noteNo, unsigned char velo);}; // ============================================================================================// このVSTを生成するための関数// ============================================================================================AudioEffect* createEffectInstance (audioMasterCallback audioMaster){//newでこのVSTを生成したポインタを返すreturn new MySynthSampleVST (audioMaster);} // ============================================================================================// このVSTの初期化// ============================================================================================MySynthSampleVST MySynthSampleVST (audioMasterCallback audioMaster) AudioEffectX (audioMaster, MY_VST_PRESET_NUM, MY_VST_PARAMETER_NUM){//VSTの初期化を行う。 //以下の関数を呼び出して入力数、出力数等の情報を設定する。//必ず呼び出さなければならない。setNumInputs (MY_VST_INPUT_NUM); //入力数の設定setNumOutputs (MY_VST_OUTPUT_NUM); //出力数の設定setUniqueID (MY_VST_UNIQUE_ID); //ユニークIDの設定 isSynth (true); //このVSTがSynthかどうかのフラグを設定。 //Synthの場合…true、Effectorの場合…false canProcessReplacing (); //このVSTが音声処理可能かどうかのフラグを設定。 //音声処理を行わないVSTはないので必ずこの関数を呼び出す。 //上記の関数を呼び出した後に初期化を行う} // ============================================================================================// 音声信号処理部分// ============================================================================================void MySynthSampleVST processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames){//入力、出力は2次元配列で渡される。//入力は-1.0f~1.0fの間で渡される。//出力は-1.0f~1.0fの間で書き込む必要がある。//sampleFramesが処理するバッファのサイズfloat* inL = inputs[0]; //入力 左用float* inR = inputs[1]; //入力 右用float* outL = outputs[0]; //出力 左用float* outR = outputs[1]; //出力 右用 // 処理されたフレーム数VstInt32 processedFrames = 0; while(getMidiMessageNum() 0){// 処理すべきフレーム数VstInt32 Frames = getNextDeltaFrames() - processedFrames;processReplacing2 (inL, inR, outL, outR, Frames); // MIDIメッセージの処理を行うmidiProc(); // 処理されたフレーム数を計算// 同時に音声信号バッファのポインタについても進める。processedFrames += Frames;inL += Frames;inR += Frames;outL += Frames;outR += Frames;} processReplacing2 (inL, inR, outL, outR, sampleFrames - processedFrames);} void MySynthSampleVST processReplacing2 (float* inL, float* inR, float* outL, float* outR, VstInt32 sampleFrames){for (int i = 0; i sampleFrames; i++){//ここで音声処理を行う。float out = 0.0f;float volume = 1.0 / (double)MAX_OSCILLATORS; // 各オシレータの振幅を取得し、出力に足し合わせる。for(int j = 0; j MAX_OSCILLATORS; j++){// オシレータの振幅を取得。out += osc[j].amplitude(); // オシレータの状態を更新する。osc[j].update();} //出力バッファへ書き込む。outL[i] = out * volume;outR[i] = out * volume;}} // MIDIメッセージをVSTに保存する。// processReplacing()の前に必ず1度だけ呼び出される。VstInt32 MySynthSampleVST processEvents (VstEvents* events){// MIDIのリストを初期化します。clearMidiMsg(); int loops = (events- numEvents); // VSTイベントの回数だけループをまわす。for (int i = 0;i loops; i++){// 与えられたイベントがMIDIならばmidimsgbufにストックするif ((events- events[i])- type == kVstMidiType){VstMidiEvent *midievent = (VstMidiEvent*)(events- events[i]);if( !addMidiMsg(midievent) ){break;}}} // 1を返さなければならないreturn 1;} // ============================================================================================// MIDIメッセージを処理する// ============================================================================================void MySynthSampleVST onMidiKeyOn (unsigned char channel, unsigned char noteNo, unsigned char velo){// OFF状態のオシレータを探すfor(int i = 0; i MAX_OSCILLATORS; i++){if(osc[i].getStatus() == VOICE_STATE_OFF){// OFF状態のオシレータをONにして検索終了osc[i].start(noteNo);break;}}} void MySynthSampleVST onMidiKeyOff (unsigned char channel, unsigned char noteNo, unsigned char velo){// ON状態でかつノートNoと一致するオシレータを探すfor(int i = 0; i MAX_OSCILLATORS; i++){if(osc[i].getStatus() == VOICE_STATE_ON osc[i].getNoteNo() == noteNo){// ON状態のオシレータをOFFにして検索終了osc[i].stop();break;}}} 【COscillator.h】 #pragma once#include math.h #define VOICE_STATE_OFF 0#define VOICE_STATE_ON 1 class CVoice{protected float elapsedFrames; //オシレータが発音を始めてから経過したフレーム数 int status; //オシレータ発音中の場合はTrueint noteNo; //オシレータの音程 float sampleRate; //サンプルレート(デフォルト 44100) public inline CVoice(void);inline ~CVoice(void); // オシレータを初期化するメンバー関数inline void init(); // 現在のオシレータの振幅を返すメンバー関数inline float amplitude(); // オシレータの状態を更新するメンバー関数inline void update(); // オシレータの動作を開始・停止させるメンバー関数inline void start(int note);inline void stop(); // オシレータのメンバ変数を設定するメンバー関数inline void setSampleRate(float newSampleRate); // オシレータの状態を取得するメンバー関数inline int getStatus() { return status; };inline int getNoteNo() { return noteNo; }; }; CVoice CVoice(){// 初期化を実施init();} CVoice ~CVoice(){} void CVoice init(){// メンバ変数を初期化するelapsedFrames = 0.0;status = VOICE_STATE_OFF;noteNo = 0;sampleRate =44100.0f;} float CVoice amplitude(){// オシレータの振幅を返すif(status == VOICE_STATE_ON){// オシレータの状態がONの時float pi = 3.14159265f; // ノートNoから周波数を計算するfloat freq = (float)(440.0 * pow(2.0, ((double)noteNo - 69.0)/12.0));; // 現在の振幅量を返すreturn (float)sin(2.0 * pi * freq * elapsedFrames / sampleRate);}else{// オシレータの状態がOFFの時 // 0を返すreturn 0.0f;}} void CVoice update(){// 経過時間を進めるelapsedFrames += 1.0f;} void CVoice start(int note){status = VOICE_STATE_ON;noteNo = note;} void CVoice stop(){init();} void CVoice setSampleRate(float newSampleRate){sampleRate = newSampleRate;} VST Tipsトップページへ(準備中) 同一カテゴリのTips 項目 No. 概要
https://w.atwiki.jp/vst_prog/pages/62.html
VST Tips(準備中) コンパイル時の注意 ここではコンパイル・ビルドを実施してVST(DLLファイル)を生成する際の注意事項について記載する。 コンパイル、ビルド時の構成について コンパイル、ビルド時の警告について コンパイル、ビルドの構成の注意 コンパイル、ビルド時の構成を「Release」に設定する。 (「Debug」でも問題ないが、デバッグに必要な処理が追加される。作成したVSTを公開する場合は「Release」にするほうがよい。また、前項(準備中)はコンパイル、ビルド構成が「Release」であることが前提となっている。) コンパイル、ビルド時の構成を設定する方法はメニュー「ツール」下あたりにある「Debug」のリストボックスから「Release」を選択する。 コンパイル、ビルド時の警告 コンパイル、ビルドの結果は画面下側にある出力ウィンドウでビルド結果を確認できる。 以下の警告「warning C4996」はもともと出るので問題ない。 それ以外の警告やエラーが出るようであれば、プロジェクトの設定や、コードの誤字脱字について再確認する。 (プロジェクト設定の詳細については前項までに説明。「同一カテゴリのTips」参照) warning C4996 strncat This function or variable may be unsafe. Consider using strncat_s instead.To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. C \Program Files\Microsoft Visual Studio 9.0\VC\include\string.h(144) 【warning C4996】 strcpy,scanf等の関数を利用すると発生する警告。 ファオーバーフロー の対策ため表示される。 以下を定義するとエラーは出なくなる。 #define _CRT_SECURE_NO_DEPRECATE 1 生成されたファイルの確認 コンパイル・ビルドが正常に完了すると、.slnファイルのあるフォルダに新しいフォルダ「Release」が作成されている。 「Release」フォルダの中に「プロジェクト名.dll」というDLLファイルがVSTである。 VST Tipsトップページへ(準備中) 同一カテゴリのTips 項目 No. 概要 VC++ プロジェクトの準備 No.1 VC++でVST用のプロジェクトを作成する No.2 VSTを作成するに当たって必要なVST SDKファイルをVC++のプロジェクトに追加する No.3 VSTを作成するに当たって必要なvstplug.defファイルを作成する No.4 VSTを作成するに当たって必要なコンパイラ、リンカ設定を追加する No.5 VSTをコンパイルするの際の注意事項
https://w.atwiki.jp/vst_prog/pages/21.html
Steinberg VST Audio Plug-Ins SDK 2.4のインストール方法(2010年4月14日) 手順概要 Steinberg VST Audio Plug-Ins SDKのインストールは大きく以下の手順で行う Steinberg 開発者アカウントの作成 Steinberg VST Audio Plug-Ins SDK 2.4のダウンロード Visual C++へのパス追加 次へ 合計: - 今日: - 昨日: -
https://w.atwiki.jp/vst_prog/pages/89.html
VST Tips(準備中) MySynthSampleVSTクラスの実装 ここでは音源に必要なクラスの定義で定義したMySynthSampleVSTクラスについて説明する。 MySynthSampleVSTの初期化 MySynthSampleVSTの初期化では初期化ルールに従い初期化を行っている。 MySynthSampleVST MySynthSampleVST (audioMasterCallback audioMaster) AudioEffectX (audioMaster, MY_VST_PRESET_NUM, MY_VST_PARAMETER_NUM){//VSTの初期化を行う。 //以下の関数を呼び出して入力数、出力数等の情報を設定する。//必ず呼び出さなければならない。setNumInputs (MY_VST_INPUT_NUM); //入力数の設定setNumOutputs (MY_VST_OUTPUT_NUM); //出力数の設定setUniqueID (MY_VST_UNIQUE_ID); //ユニークIDの設定 isSynth (true); //このVSTがSynthかどうかのフラグを設定。 //Synthの場合…true、Effectorの場合…false canProcessReplacing (); //このVSTが音声処理可能かどうかのフラグを設定。 //音声処理を行わないVSTはないので必ずこの関数を呼び出す。 //上記の関数を呼び出した後に初期化を行う} ただし、作成するものが音源(VSTi)のためisSynth()関数の引数にtrueを入れている。 isSynth (true); //このVSTがSynthかどうかのフラグを設定。 //Synthの場合…true、Effectorの場合…false MIDIメッセージをホストアプリケーションから受け取る processEvents()関数でMIDIメッセージを受け取る。 詳細については省略する。(詳しくはMIDIメッセージをホストアプリケーションから受け取る関数参照) 受け取ったMIDIメッセージの振り分け 受け取ったMIDIメッセージをメッセージごとに処理を振り分ける。 今回の音源のMIDI Controllerにあたる部分となる。 実装についてはCMidiMsgクラスからオーバーライドしたMidiProc()関数が該当する。 詳細については省略する。 MIDI ノードOn/Offメッセージを受け取った時の処理 今回の音源のVoice Controllerにあたる部分を実装する。 今回の音源の仕様で記述したとおり、ノートOnメッセージを受け取った場合、まず停止中(OFF状態)のボイスを探す。 停止中のボイスが見つかれば、そのボイスを発音(start)させ、停止中ボイスの検索を打ち切る。 void MySynthSampleVST onMidiKeyOn (unsigned char channel, unsigned char noteNo, unsigned char velo){// OFF状態のボイスを探すfor(int i = 0; i MAX_VOICES; i++){if(cvoice[i].getStatus() == VOICE_STATE_OFF){// OFF状態のボイスをONにして検索終了cvoice[i].start(noteNo);break;}}} なお、上記のコードはすべて発音中の場合、それ以上音が出ないという不具合(仕様)がある。(この仕様の修正についてはそのうち説明予定。) 次にノートOnメッセージを受け取った場合であるが、これは発音中(ON状態)かつ音程(ノートナンバー)が一致するものを探し出し、見つかればそのボイスを停止(stop)させるという処理を実施している。 void MySynthSampleVST onMidiKeyOff (unsigned char channel, unsigned char noteNo, unsigned char velo){// ON状態でかつノートNoと一致するボイスを探すfor(int i = 0; i MAX_VOICES; i++){if(cvoice[i].getStatus() == VOICE_STATE_ON cvoice[i].getNoteNo() == noteNo){// ON状態のボイスをOFFにして検索終了cvoice[i].stop();break;}}} processReplacing()関数 作成中 次へ(準備中) 同一カテゴリのTips 項目 No. 概要